import cv2
import numpy as np
import json
import os

gl_main_img = None  # 合并图像时用到的空白大图
gl_img_info_file = "info.txt"
gl_temp_dir = "./temp_result_dir"  # 默认的临时文件夹，默认将生成的切片存入其中


def __read_basic_info_from_file(src_dir):
    """
    与写入数据到文件对应的从info.txt中读取数据
    :param src_dir: 目标文件夹，必须包含info.txt
    :return: 包含图像合并所需基本信息的字典
    """
    if not os.path.exists(src_dir):
        return None
    temp_file = open("%s\\%s" % (src_dir, gl_img_info_file), 'r')
    basic_info_len_str = temp_file.readline()
    # 得到第一行的json长度，不要忽略了还有’\n‘
    step1 = len(basic_info_len_str.encode()) + 1
    basic_info_len = int(basic_info_len_str)
    # 跳过首行
    temp_file.seek(step1, 0)
    # 读取对应长度的信息
    content = temp_file.read(basic_info_len)
    img_info = json.loads(content)
    temp_file.flush()
    temp_file.close()
    return img_info


def __decode_file_name(file_name_str):
    """
    将传入的文件名拆分如将 a_b_c_d.jpg 拆分为  a  b  c  d
    :param file_name_str: 文件名字符串
    :return: 参数元组
    """
    args = file_name_str.split('_')
    result_list = []
    for i in range(0, len(args) - 1):
        result_list.append(int(args[i]))
    temp_s = args[len(args) - 1].split('.')
    result_list.append(int(temp_s[0]))
    return tuple(result_list)


def __get_file_list(tmp_dir, check_size, require_file_type):
    """
    获取文件中指定类型文件的文件名列表
    :param tmp_dir: 指定文件夹
    :param check_size: 文件的数量
    :param require_file_type:
    :return:
    """
    result_list = []
    if os.path.exists(tmp_dir):
        for i in os.listdir(tmp_dir):
            if i.endswith(require_file_type):
                result_list.append(i)
        # print(len(temp_file_list))
        if len(result_list) < check_size:
            print("图片数量不足")
            return None
        else:
            return result_list
    return None


def __generate_zeros_img(*shape):
    """
    生成一张黑色图像，并保存在self.__main_img中
    :param shape: 要生成图像的信息
    :return: 创建是否成功
    """
    global gl_main_img
    del gl_main_img
    gl_main_img = np.zeros(list(shape), dtype=np.uint8)  # 生成一张空白黑色图像
    if gl_main_img is not None:
        return True
    else:
        return False


def img_put(src_dir=None):
    """
    将指定文件夹或者默认文件夹中的图像合并为一张大图
    :param src_dir: 小图像的路径,默认为 ./temp_result_dir
    :return: 合并后的大图
    """
    if src_dir is not None:
        target_src = src_dir
    else:
        target_src = gl_temp_dir
    img_basic_info = __read_basic_info_from_file(target_src)
    if img_basic_info is None:
        print("src_dir路径无效")
        return None
    else:
        """
        切割信息写入时写入格式如下
         {"img_h": img.shape[0], "img_w": img.shape[1], "img_c": img.shape[2],
                "clip_w_pixels": clip_w_pixels, "clip_h_pixels": clip_h_pixels, "step_w": step_w,
                "step_h": step_h, "total_clip_num": total_clip_num, "clip_type": clip_type}
        """

        # 原图的 高度，宽度，通道数
        img_h = img_basic_info["img_h"]
        img_w = img_basic_info["img_w"]
        img_c = img_basic_info["img_c"]
        # clip_w_pixels = img_basic_info["clip_w_pixels"]
        # clip_h_pixels = img_basic_info["clip_h_pixels"]
        # step_w = img_basic_info["step_w"]
        # step_h = img_basic_info["step_h"]
        # 文件夹中应该包含的切片数目
        total_clip_num = img_basic_info["total_clip_num"]
        # 切片的文件类型
        clip_file_type = img_basic_info["clip_type"]
        # 得到对应文件夹中对应类型文件的列表
        img_list = __get_file_list(target_src, total_clip_num, clip_file_type)
        # 遍历上面得到的文件列表，并将切片合并到大图中
        if img_list is not None:
            if __generate_zeros_img(img_h, img_w, img_c):
                for img_name in img_list:
                    # 根据文件的名字来确定本张图片在原图中的位置，此处通过解析文件名字获得一个范围
                    top, bottom, left, right = __decode_file_name(img_name)
                    # 读取图像的数据
                    temp_img = cv2.imread("%s\\%s" % (target_src, img_name))
                    # 将数据覆盖到准备好的空白矩阵中
                    gl_main_img[top:bottom, left:right] = temp_img
        return gl_main_img
